﻿using System.Diagnostics;
using System.Security.Claims;
using Duende.IdentityModel;
using Duende.IdentityServer.Models;
using Duende.IdentityServer.Validation;
using Service.Auth.Api.Application.Query;
using Service.Auth.Infrastructure.Utils;
using Service.Core.Redis.Services;
using Service.Framework.ApplicationEventBus;
using Service.Framework.Packet;
using Service.Auth.Api.Application.Query;

namespace Service.Auth.Api.Application.IdsValidator
{
    /// <summary>
    /// 角色授权用户名密码验证器
    /// </summary>
    public class RoleResourceOwnerPasswordValidator(
        IHttpContextAccessor httpContextAccessor,
        IApplicationEventBus applicationEventBus,
        IRedisService redisService, UserQueryService userQueryService, SystemQueryService systemQueryService)
        : BaseResourceOwnerValidator(httpContextAccessor, applicationEventBus, redisService, userQueryService, systemQueryService), IResourceOwnerPasswordValidator
    {

        /// <inheritdoc/>
        public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
        {
            var sw = new Stopwatch();
            sw.Start();
            var userId = string.Empty;
            try
            {
                var accountLock = await VerifyAccountLock(context.UserName);
                if (accountLock.anyLock)
                {
                    context.Result = new GrantValidationResult(TokenRequestErrors.InvalidTarget, accountLock.msg,
                        new Dictionary<string, object>
                    {
                        { "code", StatusCode.RepeatOperation }
                    });
                    return;
                }
                var valiDate = await ValidateAsync(context.UserName, context.Request.ClientId);
                if (valiDate.result != null)
                {
                    context.Result = valiDate.result;
                    return;
                }
                var user = valiDate.user;
                var salt = user?.PasswordValueObject?.Salt ?? "";
                if (!HashCrypto.Validate(context.Password, salt, user?.PasswordValueObject ?? ""))
                {
                    context.Result = new GrantValidationResult(TokenRequestErrors.InvalidTarget,
                        "登录失败，用户名和密码不正确。");
                    await SetAccountErrorCount(context.UserName);
                    return;
                }
                userId = user.Id.ToString();
                var roleIds = user.UserSystemRoles.Select(s => s.RoleId).ToList();
                var roles = user.UserSystemRoles.Select(s => s.RoleNum).ToList();
                var claims = new List<Claim>
                {
                    new(JwtClaimTypes.Subject, user.Id.ToString()),
                    new("tenant_id", user.TenantId),
                };
                var claim = roles.Select(s =>
                    new Claim(JwtClaimTypes.Role, s)).ToArray();
                claims.AddRange(claim);

                // 验证账号
                context.Result = new GrantValidationResult
                (
                    subject: user.Id.ToString(),
                    authenticationMethod: "custom",
                    claims: claims
                );
                await Task.CompletedTask;
            }
            catch (Exception ex)
            {
                context.Result = new GrantValidationResult()
                {
                    IsError = true,
                    Error = ex.Message
                };
            }
            finally
            {
                sw.Stop();
            }
        }
    }
}